package no.uib.kwikktaim.gui;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.media.Player;
import javax.media.Time;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import no.uib.kwikktaim.utils.ByteConvertor;
import no.uib.kwikktaim.utils.MovieThumbnail;

/**
 * Class for generating keyframes. Beware of angry spaghetticode.
 * @author Übermensch
 *
 */
public class KeyFrames extends JFrame implements ActionListener, Serializable {
	MainWindow mw;
	JButton frame1;
	JPanel panel;
	JScrollPane scrollPane;
	Player player;
	Time time;
	double runtime;
	double node;
	GeneratingKeyframesDialog wait;
	MediaViewer mv;

	/**
	 * Setup the keyframe window and generate keyframes
	 * @param mw the main window
	 */
	public KeyFrames(MainWindow mw) {
		super("Key Frames");

		this.setLayout(new FlowLayout());
		this.setResizable(false);

		panel = new JPanel();

		// Please wait dialog
		wait = new GeneratingKeyframesDialog();

		// Run the slow stuff in own thread
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                setupKeyframes();
            }
        });

		scrollPane = new JScrollPane(panel);
		scrollPane.setPreferredSize(new Dimension(800,175));
		scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		scrollPane.getHorizontalScrollBar().setUnitIncrement(20);
		this.add(scrollPane);

		pack();

		// Set it right under the player window
		Point p = mw.getLocation();
		p.x = (int) p.getX() - (this.getWidth() - mw.getWidth())/2;
		p.y = (int) p.getY() + mw.getHeight()+5;

		// We don't want it to be outside the screen..
		if(p.y + this.getHeight() > this.getToolkit().getScreenSize().getHeight())
			p.y = (int) (this.getToolkit().getScreenSize().getHeight() - this.getHeight()*2);

		// Place the frame
		this.setLocation(p);



		mv = mw.getPlayer();
		player = mv.getMediaPlayer();
		runtime = player.getDuration().getSeconds();
		this.mw = mw;


	}

	/**
	 * If we already have the keyframes
	 * @param list list with keyframes
	 * @param mw the main window
	 */
	public KeyFrames(ArrayList<Image> list, MainWindow mw) {
		super("Key Frames");
		this.mw = mw;

		mv = mw.getPlayer();
		player = mv.getMediaPlayer();
		runtime = player.getDuration().getSeconds();

		this.setLayout(new FlowLayout());
		this.setResizable(false);

		panel = new JPanel();
		int i = 0;


		for (Image image : list) {
			node = runtime / 24 * i;
			DecimalFormat pos = new DecimalFormat("#0.00 seconds");
			String position = pos.format(node);

			JButton j = new JButton();
			JLabel label = new JLabel(position);
			ImageIcon icon = new ImageIcon(image);
			j.setIcon(icon);
			j.setText(position);

			// Hack to get time for actionlistener.
			j.setToolTipText(new Double(node).toString());


			j.addActionListener(this);
			j.setVerticalTextPosition(SwingConstants.BOTTOM);
			j.setHorizontalTextPosition(SwingConstants.CENTER);
			j.setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()+25));

			panel.add(j);
			i++;
		}

		scrollPane = new JScrollPane(panel);
		scrollPane.setPreferredSize(new Dimension(800,175));
		scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		scrollPane.getHorizontalScrollBar().setUnitIncrement(20);
		this.add(scrollPane);

		pack();

		// Set it right under the player window
		Point p = mw.getLocation();
		p.x = (int) p.getX() - (this.getWidth() - mw.getWidth())/2;
		p.y = (int) p.getY() + mw.getHeight()+5;

		// We don't want it to be outside the screen..
		if(p.y + this.getHeight() > this.getToolkit().getScreenSize().getHeight())
			p.y = (int) (this.getToolkit().getScreenSize().getHeight() - this.getHeight()*2);

		// Place the frame
		this.setLocation(p);

		// Show the frame
		this.setVisible(true);
	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		JButton j = (JButton) arg0.getSource();
		mw.setTime(new Double(j.getToolTipText())-0.7);
	}

	private void setupKeyframes() {

		// Fetch keyframes
		ArrayList<Image> list = MovieThumbnail.createImageFromURL(mw.getPlayer().getCurrentURL());

		// Write to file
		serializeIt(list);

		// Add keyframes to UI
		int i = 0;
		for (Image image : list) {
			node = runtime / 24 * i;
			DecimalFormat pos = new DecimalFormat("#0.00 seconds");
			String position = pos.format(node);

			JButton j = new JButton();
			JLabel label = new JLabel(position);
			ImageIcon icon = new ImageIcon(image);
			j.setIcon(icon);
			j.setText(position);

			// Hack to get time for actionlistener.
			j.setToolTipText(new Double(node).toString());


			j.addActionListener(this);
			j.setVerticalTextPosition(SwingConstants.BOTTOM);
			j.setHorizontalTextPosition(SwingConstants.CENTER);
			j.setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()+25));

			panel.add(j);
			i++;
		}

		// Remove the wait dialog
		wait.removeDialog();
		wait = null;

		// Show the frame
		this.setVisible(true);

	}


	/**
	 * Encode a string using RLE (?).
	 * @param source
	 * @return
	 */
	public String encode(String source) {
		StringBuffer dest = new StringBuffer();
		int counter = -1;
		for (int i = 0; i < source.length() - 1; i++) {
			if (source.charAt(i) != source.charAt(i + 1)) {
				dest.append(i - counter);
				dest.append(source.charAt(i));
				counter = i;
			}
		}
		dest.append(source.length() - counter - 1);
		dest.append(source.charAt(source.length() - 1));
		return dest.toString();
	}

	/**
	 * Serializes a list of images into a list of bytes.
	 * @param obj
	 */
	private void serializeIt(ArrayList<Image> obj) {
		ArrayList<Byte[]> byteList = new ArrayList<Byte[]>();

		try {
			File f = new File("cache"+ File.separator + Math.abs(mw.getPlayer().getCurrentURL().hashCode()) + ".srz");

			if(!f.exists()) f.createNewFile();

			FileOutputStream fout = new FileOutputStream(f);
			ObjectOutputStream oos = new ObjectOutputStream(fout);
			for (Image img : obj) {
				BufferedImage bu = new BufferedImage(img.getWidth(null),img.getHeight(null),BufferedImage.TYPE_INT_RGB);
				ByteArrayOutputStream bas = new ByteArrayOutputStream();

				Graphics g = bu.getGraphics();
				g.drawImage(img,0,0,null);
				g.dispose();

				ImageIO.write(bu,"jpg", bas);
				byteList.add(ByteConvertor.byteFromByte(bas.toByteArray()));
			}
			oos.writeObject(byteList);
			oos.close();
			fout.close();
		}
		catch (Exception e) { e.printStackTrace(); }
	}

}
